package net.gdface.service.client;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.facelib.u4fdb.localdb.UrlBean;
import net.gdface.sdk.CodeInfo;
import net.gdface.service.search.ImgInfo;
import net.gdface.service.search.RemoteImage;
import net.gdface.service.search.RemoteImage.ActionIfNoTimeup;
import net.gdface.service.search.RemoteImageWOC;
import net.gdface.utils.Assert;
import net.gdface.utils.Judge;
import net.gdface.worker.NoTimeupException;
import net.gdface.worker.RetryException;
import net.gdface.worker.WorkData;
import net.gdface.worker.WorkDataWithURI;

public abstract class FetchAbstract implements FetchImage{
	static final Logger logger = LoggerFactory.getLogger(FetchAbstract.class);

	public FetchAbstract() {
		super();
	}

	@Override
	public String fetchSync(WorkDataWithURI woc, boolean openReferer, boolean throwRetryIfFail, ActionIfNoTimeup actionIfNoTimeup) throws InterruptedException,
			RetryException, NoTimeupException {
				// 队列中有相同URI的任务对象,返回null;
				if(null!=WorkData.WOKING_DATA.putIfAbsent(woc)){
					logger.warn("{} 已经在当前工作对象中", woc.getURI());
					return null;
				}
				try {
					//从工作对象中获取局部变量
					ImgInfo imginfo =woc.getVariables(WorkDataJSON.VAR_IMGINFO);
					RemoteImage rmi=null;
					rmi=woc.getVariables(WorkDataJSON.VAR_REMOTEIMAGE);
					//同步模式下，imginfo.isRetryed()时，可能是下载失败，也可能是保存失败，
					//所以在这里必须要判断RemoteImage对象的有效性，如果有效，就不再重复下载
					//重试状态下的woc要重新执行needDownload来判断是不是需要下载
					//因为目前的机制中，重试的woc排队期间被移出了WORK_DATA，有可能有同url的其他woc已经被执行过。数据库中对应的url已经更新了
					//所以必须重新从数据库读取数据
					if(needDownload(woc)){
						if (imginfo.isRetryed()) {
							// 如果是重试，则上次的对象还在容器中，不必创建新对象,只需要重置RemoteImage的retry标记					
							if (!rmi.isValidImage()) {
								rmi.setRetryed(true);
								rmi.downloadSync(actionIfNoTimeup, openReferer);
							}//else 有效图像就不用再下载
						}else{
							if (null == rmi) {
								rmi = new RemoteImage(imginfo.getLocaction(), imginfo.getReferer(), !throwRetryIfFail);
								woc.setVariables(WorkDataJSON.VAR_REMOTEIMAGE, rmi);
							}
							rmi.downloadSync(actionIfNoTimeup, openReferer);
						}			
					}
					//重新从容器获取对象 needDownload为false时有可能会生成RemoteImage
					if (null!=(rmi=woc.getVariables(WorkDataJSON.VAR_REMOTEIMAGE))&&needSave(woc)) {
						save(woc);
					}
				} catch (RuntimeException e) {
					onRuntimeException(e, woc);
				} finally {
					recordStatus(woc);
					WorkData.WOKING_DATA.remove(woc);
				}	
				return isFaceImage(woc);
			}

	@Override
	public String fetchSyncSleepIfNoTimeup(WorkDataWithURI woc, boolean openReferer, boolean throwRetryIfFail) throws InterruptedException,
			RetryException {
				return fetchSync(woc,openReferer,throwRetryIfFail, ActionIfNoTimeup.SLEEP);
			}

	@Override
	public boolean fetchAsync(ActionIfNoTimeup throwIfNotOntime, RemoteImageWOC woc) throws NoTimeupException, InterruptedException {
		// 队列中有相同URI的任务对象,抛出延期执行异常,
		WorkData old = WorkData.WOKING_DATA.putIfAbsent(woc);
		if(null!=old){
			if(old==woc){
				logger.warn("=======");
				return false;
			}
			throw new NoTimeupException();
		}
		//从工作对象中获取局部变量
		ImgInfo imginfo = woc.getVariables(WorkDataJSON.VAR_IMGINFO);		
		boolean submit=false;
		try {
			RemoteImage rmi;
			//异步模式下，imginfo.isRetryed()只代表下载失败,
			//但imginfo.isRetryed()为true时,还要再执行needDownload(),以重新从数据库中获取最新的urlBean
			//因为目前的机制中，重试的woc排队期间被移出了WORK_DATA，有可能有同url的其他woc已经被执行过。数据库中对应的url已经更新了
			if (needDownload(woc)) {				
				if(null==(rmi=woc.getVariables(WorkDataJSON.VAR_REMOTEIMAGE))){
					rmi = new RemoteImage(imginfo.getLocaction(), imginfo.getReferer(), imginfo.isRetryed());
					woc.setVariables(WorkDataJSON.VAR_REMOTEIMAGE, rmi);
				}else if(imginfo.isRetryed())//如果是retry，则上次的对象还在容器中，不必创建新对象,只需要重置retry标记					
					rmi.setRetryed(true);
				rmi.downloadAsyn(throwIfNotOntime, rmi.isRetryed(), woc);
				submit=true;
			} else if(null!=(rmi=woc.getVariables(WorkDataJSON.VAR_REMOTEIMAGE))){
				//重新从容器获取对象 needDownload为false时有可能会生成RemoteImage
				// 是否需要保存，交给 SaveWorker判断
				woc.onValidImage();
				submit = true;
			}			
		}finally {
			if(!submit)
				WorkData.WOKING_DATA.remove(woc);
		}
		return submit;
	}

	@Override
	public boolean fetchAsyncSleepIfNoTimeup(RemoteImageWOC woc) throws InterruptedException {
		return fetchAsync(ActionIfNoTimeup.SLEEP,woc);
	}

	@Override
	public boolean fetchAsyncThrowIfNoTimeup(RemoteImageWOC woc) throws NoTimeupException {
		try {
			return fetchAsync(ActionIfNoTimeup.THROW,woc);
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 是否为包含人脸的有效图片
	 * @param woc 
	 * 
	 * @return
	 */
	String isFaceImage(WorkData woc) {
		UrlBean urlBean=woc.getVariables(WorkDataJSON.VAR_URLBEAN);
		CodeInfo[] codes=woc.getVariables(WorkDataJSON.VAR_CODES);
		Assert.notNull(urlBean, "bean");
		boolean valid=false ;
		Status s = Status.valueOf(urlBean.getStatus());
		switch (s) {
		case NOT_FACE:
		case TOO_SMALL:
		case TOO_LARGE:
		case NOTIMAGE:
		case ZERODATA:
		case UNSUPIMAGE:
		case DEADHOST:
		case ERRORURL:
		case ERRIMAGE:
		case TIMEOUT:
			valid = false;
			break;
		case SAVED_LOCAL:
		case FAIL_SAVEDB:
		case FAIL_SAVELOCAL:
		case UNEXP:
			valid=!Judge.isEmpty(codes);
			break;
		case FACE_IMG:
		case SAVED_INDB:
		case DUPINDB:
			valid = true;
			break;
		default:
			valid =false;
			break;
		}
		return valid?urlBean.getMd5():null;
	}

}